#include "stdio.h"
#include "stdint.h"
#include "string.h"
#include "float.h"
#include "math.h"
#include "kfifo.h"
#include "FeedID.h"
#include "FeedIDIot.h"
#include "FeedFrame.h"


uint8_t g_uikFIFOFrame[1024];
KFIFO g_typekFIFOFrame = {.in = 0, .out = 0, .size = sizeof(g_uikFIFOFrame) - 1, .data = g_uikFIFOFrame};


/* securely comparison of double-point variables */
static int8_t compare_double(double a, double b)
{
    double maxVal = fabs(a) > fabs(b) ? fabs(a) : fabs(b);
    return (fabs(a - b) <= maxVal * DBL_EPSILON);
}

int8_t cFeedFrameAddx(uint16_t usID, uint8_t ucType, int32_t iValue, float fValue, double dValue, void *pvDatas, int32_t iLength)
{
    uint16_t usLength = (uint16_t)ucType << 12;
    uint8_t ucDatas[4], i;

    switch(ucType)
    {
        case FEED_FRAME_TYPE_INT :
            for(i = 0; ((iValue != 0) || (i == 0)); iValue >>= 8, ++i)
            {
                ucDatas[i] = iValue;
            }

            usLength |= i;
            pvDatas = ucDatas;
            break;

        case FEED_FRAME_TYPE_FLOAT :
            if(compare_double(fValue, dValue) != 0)
            {
                usLength |= 4;
                pvDatas = &fValue;
            }
            else
            {
                usLength |= 8;
                pvDatas = &dValue;
            }
            break;

        case FEED_FRAME_TYPE_STRING :
        case FEED_FRAME_TYPE_RAW :
            /* 无数据 */
            if(iLength <= 0)
                return 2;

            usLength |= iLength;
            break;


        default : return 1;
    }

    kfifo_in(&g_typekFIFOFrame, &usID, 2);
    kfifo_in(&g_typekFIFOFrame, &usLength, 2);
    kfifo_in(&g_typekFIFOFrame, pvDatas, usLength & 0xFFF);

    return 0;
}

int8_t cFeedFrameDecode(uint8_t ucType, void *pvDatas, int32_t iSizeIn)
{
    uint8_t *pucDatas = pvDatas;
    FeedFrameType typeFrame;
    int32_t iLength;

    if(pvDatas == NULL)
        return 1;

    while(iSizeIn > 0)
    {
        /* 读取头部信息 */
        memcpy(&typeFrame, pucDatas, 2);
        iLength = 2;

        typeFrame.get      = (ucType & 1) != 0;
        typeFrame.response = (ucType & 2) != 0;

        /* 读取数据信息 */
        if((typeFrame.get == 0) || (typeFrame.response != 0))
        {
            memcpy((uint8_t *)&typeFrame + 2, pucDatas + 2, 2);
            iLength = typeFrame.length + 4;

            if((typeFrame.length > sizeof(typeFrame.datas)) || (typeFrame.length > iSizeIn - 4))
                return 2;

            /* 复制待设置的数据 */
            memcpy(typeFrame.datas, pucDatas + 4, typeFrame.length);
        }

        /* 解析 ID 数据 */
        if(typeFrame.response == 0)
            cFeedIDIotDecode(&typeFrame);
        else
            cFeedIDDecode(&typeFrame);

        pucDatas += iLength;
        iSizeIn  -= iLength;
    }

    return 0;
}
